home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 August: Tool Chest / Dev.CD Aug 94.toast / Sample Code / AppsToGo / Kibitz / File.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-24  |  22.9 KB  |  875 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** File:            file.c
  5. ** Some code from:  Traffic Light 2.0 version, by Keith Rollin & John Harvey
  6. ** Modified by:     Eric Soldan
  7. **
  8. ** Copyright © 1990-1992 Apple Computer, Inc.
  9. ** All rights reserved. */
  10.  
  11.  
  12.  
  13. /*****************************************************************************/
  14.  
  15.  
  16.  
  17. #include "Kibitz.h"                /* Get the Kibitz includes/typedefs, etc.    */
  18. #include "KibitzCommon.h"        /* Get the stuff in common with rez.        */
  19. #include "Kibitz.protos"        /* Get the prototypes for Kibitz.            */
  20.  
  21. #ifndef __ALIASES__
  22. #include <Aliases.h>
  23. #endif
  24.  
  25. #ifndef __ERRORS__
  26. #include <Errors.h>
  27. #endif
  28.  
  29. #ifndef __MEMORY__
  30. #include <Memory.h>
  31. #endif
  32.  
  33. #ifndef __PACKAGES__
  34. #include <Packages.h>
  35. #endif
  36.  
  37. #ifndef __TOOLUTILS__
  38. #include <ToolUtils.h>
  39. #endif
  40.  
  41. #ifndef __UTILITIES__
  42. #include <Utilities.h>
  43. #endif
  44.  
  45.  
  46.  
  47. /*****************************************************************************/
  48.  
  49.  
  50.  
  51. static Boolean    gIncNewFileNumFlag = true;
  52.  
  53.  
  54.  
  55. /*****************************************************************************/
  56. /*****************************************************************************/
  57.  
  58.  
  59.  
  60. /* This function disposes of the document.  It checks to see if a file is
  61. ** currently open for the document.  If it is, then the document is closed.
  62. ** Once there is no open file for the document, the memory occupied by the
  63. ** document is released. */
  64.  
  65. #pragma segment File
  66. OSErr    AppDisposeDocument(FileRecHndl frHndl)
  67. {
  68.     OSErr        err;
  69.     Handle        snd;
  70.  
  71.     err = noErr;
  72.  
  73.     if (frHndl) {
  74.         SetOpponentType(frHndl, kOnePlayer);
  75.             /* Disconnect from opponent. */
  76.  
  77.         if ((*frHndl)->fileState.fss.vRefNum != kInvalVRefNum)
  78.             err = FSClose((*frHndl)->fileState.refNum);
  79.                 /* Close the file, if opened. */
  80.  
  81.         DisposeHandle((Handle)(*frHndl)->doc.legalMoves);
  82.         DisposeHandle((Handle)(*frHndl)->doc.gameMoves);
  83.         snd = (*frHndl)->doc.sound;
  84.         if (snd)
  85.             DisposeHandle(snd);
  86.                 /* Release all handles hanging off the document. */
  87.  
  88.         DisposeHandle((Handle)frHndl);
  89.             /* Release memory for the document handle. */
  90.     }
  91.  
  92.     return(err);
  93. }
  94.  
  95.  
  96.  
  97. /*****************************************************************************/
  98.  
  99.  
  100.  
  101. /* This function returns whether or not the document is dirty. */
  102.  
  103. #pragma segment File
  104. Boolean    AppDocumentDirty(FileRecHndl frHndl)
  105. {
  106.     return((*frHndl)->fileState.docDirty);
  107. }
  108.  
  109.  
  110.  
  111. /*****************************************************************************/
  112.  
  113.  
  114.  
  115. /* This function creates a new document.  A handle is created as the
  116. ** reference to the document.  Header information is placed in this handle.
  117. ** The application-specific data follows this header information.  The
  118. ** handle is returned (or nil upon failure), and typically the handle is
  119. ** then stored in the refCon field of the window.  Note that this is a
  120. ** convention, and is not mandatory.  This allows a document to exist that
  121. ** has no window.  A document with no window is useful when the application
  122. ** is called from the finder in response to a print request.  The document
  123. ** can be loaded and printed without involving a window on the screen. */
  124.  
  125.  
  126. #pragma segment File
  127. OSErr    AppNewDocument(FileRecHndl *returnHndl, short winNameType)
  128. {
  129.     static short    untitledCount;
  130.     FileRecHndl        frHndl;
  131.     FileRecPtr        frPtr;
  132.     Str255            untitled;
  133.     StringPtr        pstr;
  134.     MoveListHndl    legalMovesHndl;
  135.     GameListHndl    gameMovesHndl;
  136.  
  137.     *returnHndl = nil;
  138.  
  139.     frHndl = (FileRecHndl)NewHandle(sizeof(FileRec));
  140.     if (frHndl) {
  141.  
  142.         GetIndString(untitled, rMiscStrings, winNameType);
  143.         frPtr = *frHndl;
  144.         frPtr->fileState.docDirty    = false;
  145.         frPtr->fileState.readOnly    = false;
  146.         frPtr->fileState.fss.vRefNum = kInvalVRefNum;
  147.         frPtr->fileState.window      = nil;
  148.         pstr = frPtr->fileState.fss.name;
  149.         pcpy(pstr, untitled);
  150.         if (gIncNewFileNumFlag) ++untitledCount;
  151.         pcatdec(pstr, untitledCount);
  152.  
  153.         legalMovesHndl = (MoveListHndl)NewHandle(0);
  154.         if (!legalMovesHndl) {
  155.             DisposeHandle((Handle)frHndl);
  156.             return(memFullErr);
  157.         }
  158.  
  159.         gameMovesHndl = (GameListHndl)NewHandle(0);
  160.         if (!gameMovesHndl) {
  161.             DisposeHandle((Handle)frHndl);
  162.             DisposeHandle((Handle)legalMovesHndl);
  163.             return(memFullErr);
  164.         }
  165.  
  166.         NewGame(frHndl);        /* Initialize the game. */
  167.  
  168.         frPtr = *frHndl;
  169.         frPtr->doc.legalMoves = legalMovesHndl;
  170.         frPtr->doc.gameMoves  = gameMovesHndl;
  171.         if (winNameType == ksMssgName) frPtr->doc.myColor = kMessageDoc;
  172.  
  173.         *returnHndl = frHndl;
  174.         return(noErr);            /* All is well. */
  175.     }
  176.  
  177.     return(memFullErr);
  178. }
  179.  
  180.  
  181.  
  182. /*****************************************************************************/
  183.  
  184.  
  185.  
  186. #pragma segment File
  187. OSErr    AppOpenDocument(FileRecHndl *result, FSSpecPtr fileToOpen, char permission)
  188. {
  189.     StandardFileReply    reply;
  190.     short                fileRefNum;
  191.     FileRecHndl            frHndl;
  192.     OSErr                err;
  193.     FSSpec                myFileSpec;
  194.     DialogPtr            openDialog;
  195.     short                item, winNameType;
  196.  
  197.     *result = nil;        /* Assume we will fail. */
  198.  
  199.     if (!fileToOpen) {
  200.         if (DisplayGetFile(&reply))        /* Let the user decide which file. */
  201.             myFileSpec = reply.sfFile;    /* User's choice.                   */
  202.         else
  203.             return(userCanceledErr);    /* User canceled. */
  204.     }
  205.     else
  206.         myFileSpec = *fileToOpen;        /* Pre-designated file to open. */
  207.  
  208.     winNameType = ksOrigName;
  209.     if (reply.sfType != gameFileType) winNameType = ksMssgName;
  210.  
  211.     IncNewFileNum(false);
  212.     err = AppNewDocument(&frHndl, winNameType);
  213.     IncNewFileNum(true);
  214.     if (err) return(err);
  215.         /* We couldn't create an empty document, so give it up. */
  216.  
  217.     err = HOpen(myFileSpec.vRefNum, myFileSpec.parID,
  218.                 myFileSpec.name, permission, &fileRefNum);
  219.  
  220.     if (err == opWrErr) {
  221.  
  222.         ParamText(myFileSpec.name, nil, nil, nil);
  223.         openDialog = GetCenteredDialog(rOpenReadOnly, nil, nil, (WindowPtr)-1L);
  224.         if (!openDialog) {
  225.             AppDisposeDocument(frHndl);
  226.             return(err);
  227.         }
  228.  
  229.         OutlineDialogItem(openDialog, kOpenYes);
  230.         DoSetCursor(&qd.arrow);
  231.         ModalDialog(gKeyEquivFilterUPP, &item);
  232.         DisposeDialog(openDialog);
  233.         if (item != kOpenYes) return(userCanceledErr);
  234.  
  235.         (*frHndl)->fileState.readOnly = true;
  236.         err = HOpen(myFileSpec.vRefNum, myFileSpec.parID,
  237.                     myFileSpec.name, fsRdPerm, &fileRefNum);
  238.     }
  239.  
  240.     if (err) {
  241.         AppDisposeDocument(frHndl);
  242.         return(err);
  243.     }
  244.  
  245.     (*frHndl)->fileState.fss    = myFileSpec;
  246.     (*frHndl)->fileState.refNum = fileRefNum;
  247.  
  248.     err = AppReadDocument(frHndl, reply.sfType);
  249.     if (err) {
  250.         AppDisposeDocument(frHndl);
  251.         return(err);
  252.     }
  253.  
  254.     if ((*frHndl)->fileState.readOnly) {
  255.         FSClose((*frHndl)->fileState.refNum);
  256.         (*frHndl)->fileState.fss.vRefNum = kInvalVRefNum;
  257.     }        /* If it's read-only, we don't need the file left open. */
  258.  
  259.     *result = frHndl;
  260.     return(err);
  261. }
  262.  
  263.  
  264.  
  265. /*****************************************************************************/
  266.  
  267.  
  268.  
  269. #pragma segment File
  270. OSErr    AppSaveDocument(FileRecHndl frHndl, WindowPtr window, short saveMode)
  271. {
  272.     Str255                closeOrQuit;
  273.     short                item, gameStatus;
  274.     StandardFileReply    reply;
  275.     OSErr                err;
  276.     short                fileRefNum;
  277.     DialogPtr            saveDialog;
  278.     Boolean                doPrompt;
  279.     Boolean                youLose;
  280.     OSType                theFileType;
  281.  
  282. /*    When entering, saveMode is set to the menu command number of the
  283. **    the item that prompted this.  Current settings are iSave, iSaveAs,
  284. **    iClose, and iQuit. */
  285.  
  286.     if (saveMode != iSaveAs) {                        /* If regular save... */
  287.         if (!AppDocumentDirty(frHndl))                /* If file clean...   */
  288.             return(noErr);                            /* Consider it saved. */
  289.     }
  290.  
  291.     pcpy(reply.sfFile.name, (*frHndl)->fileState.fss.name);
  292.  
  293.     if ((saveMode == iClose) || (saveMode == iQuit)) {
  294.         /* If implicit save... */
  295.  
  296.         GetIndString(closeOrQuit, rMiscStrings,
  297.                      (saveMode == iClose) ? ksClosing : ksQuitting);
  298.         ParamText(reply.sfFile.name, closeOrQuit, nil, nil);
  299.  
  300.         gameStatus = GameStatus(frHndl);
  301.         youLose = ((gameStatus == kYouLose) || (gameStatus == kYouLoseOnTime));
  302.         if ((gameStatus == kWhiteResigns) && ((*frHndl)->doc.myColor == WHITE))
  303.             youLose = true;
  304.         if ((gameStatus == kBlackResigns) && ((*frHndl)->doc.myColor == BLACK))
  305.             youLose = true;
  306.         if (youLose)
  307.             saveDialog = GetCenteredDialog(rNoYesCancel, nil, window, (WindowPtr)-1L);
  308.         else
  309.             saveDialog = GetCenteredDialog(rYesNoCancel, nil, window, (WindowPtr)-1L);
  310.  
  311.         if (saveDialog) {
  312.             OutlineDialogItem(saveDialog, kSaveYes);
  313.             DoSetCursor(&qd.arrow);
  314.             ModalDialog(gKeyEquivFilterUPP, &item);
  315.             DisposeDialog(saveDialog);
  316.             if (youLose)
  317.                 if (item != kSaveCanceled)
  318.                     item = (item == kSaveYes) ? kSaveNo : kSaveYes;
  319.         }
  320.         else
  321.             item = kSaveYes;
  322.  
  323.         if (item != kSaveYes) {
  324.             err = noErr;
  325.             if (item == kSaveCanceled) err = userCanceledErr;
  326.             return(err);
  327.         }
  328.     }
  329.  
  330.     doPrompt = (
  331.         (saveMode == iSaveAs) ||
  332.         ((*frHndl)->fileState.fss.vRefNum == kInvalVRefNum)
  333.     );
  334.  
  335.     if (doPrompt) {
  336.         /* Prompt with SFGetFile if doing a Save As or have never saved before. */
  337.  
  338.         if (!DisplayPutFile(&reply))
  339.             return(userCanceledErr);
  340.                 /* User canceled the save. */
  341.  
  342.         if ((*frHndl)->fileState.fss.vRefNum != kInvalVRefNum)
  343.             FSClose((*frHndl)->fileState.refNum);
  344.                 /* Close the old file.  Don't respond to any error here because
  345.                 ** the user may be trying to do a save-as because their old file
  346.                 ** is bad.  If we fail to close the old file, and then respond
  347.                 ** to the error, the user won't get the opportunity to save
  348.                 ** their document to a new file.
  349.                 */
  350.  
  351.         theFileType = gameFileType;
  352.         if ((*frHndl)->doc.myColor == kMessageDoc) theFileType = mssgFileType;
  353.  
  354.         err = Create_OpenFile(&reply.sfFile, &fileRefNum, theFileType);
  355.         if (err) {
  356.             (*frHndl)->fileState.fss.vRefNum = kInvalVRefNum;
  357.             return(err);
  358.         }
  359.  
  360.         (*frHndl)->fileState.fss    = reply.sfFile;
  361.         (*frHndl)->fileState.refNum = fileRefNum;
  362.             /* This is the new file. */
  363.  
  364.         if (window) AppNewWindowTitle(window);
  365.     }
  366.  
  367.     err = AppWriteDocument(frHndl);
  368.     if (err)
  369.         return(err);
  370.  
  371.     (*frHndl)->fileState.docDirty = false;
  372.     (*frHndl)->fileState.readOnly = false;
  373.     return(noErr);
  374. }
  375.  
  376.  
  377.  
  378. /*****************************************************************************/
  379.  
  380.  
  381.  
  382. /* ConvertOldToNewSFReply
  383. **
  384. ** struct StandardFileReply {            struct SFReply {
  385. **     Boolean     sfGood;                <-    Boolean good;
  386. **     Boolean     sfReplacing;        <-    Boolean copy;
  387. **     OSType         sfType;                <-    OSType fType;
  388. **     FSSpec        sfFile;
  389. **                     vRefNum;        <-    real vRefnum from (short vRefNum)
  390. **                     parID;            <-    real dirID from (short vRefNum)
  391. **                     name;            <-    Str63 fName;
  392. **     ScriptCode    sfScript;            <-    iuSystemScript
  393. **     short         sfFlags;            <-    0
  394. **     Boolean     sfIsFolder;            <-    false
  395. **     Boolean     sfIsVolume;            <-    false
  396. **     long        sfReserved1;        <-    0
  397. **     short        sfReserved2;        <-    0
  398. ** };
  399. **}; */
  400.  
  401. #pragma segment File
  402. void    ConvertOldToNewSFReply(SFReply *oldReply, StandardFileReply *newReply)
  403. {
  404.     OSErr    err;
  405.     long    ignoredProcID;
  406.  
  407.     newReply->sfGood        = oldReply->good;
  408.     newReply->sfReplacing    = oldReply->copy;        /* Correct assignment? */
  409.     newReply->sfType        = oldReply->fType;
  410.  
  411.     err = GetWDInfo(oldReply->vRefNum,
  412.                     &newReply->sfFile.vRefNum,
  413.                     &newReply->sfFile.parID,
  414.                     &ignoredProcID);
  415.     BlockMove((Ptr)&oldReply->fName,
  416.               (Ptr)&newReply->sfFile.name,
  417.               oldReply->fName[0]+1);
  418.  
  419.     /* Punt on the rest. */
  420.     newReply->sfScript        = iuSystemScript;
  421.     newReply->sfFlags        = 0;
  422.     newReply->sfIsFolder    = false;
  423.     newReply->sfIsVolume    = false;
  424.     newReply->sfReserved1    = 0;
  425.     newReply->sfReserved2    = 0;
  426. }
  427.  
  428.  
  429.  
  430. /*****************************************************************************/
  431.  
  432.  
  433.  
  434. /* Create_OpenFile
  435. **
  436. ** Opens the file specified by the passed FSSpec, creating it if it doesn't
  437. ** already exist. Refturns the refnum of the open file to the application.
  438. ** File Manager errors are reported and returned. */
  439.  
  440. #pragma segment File
  441. OSErr    Create_OpenFile(FSSpec *file, short *refNum, OSType theFileType)
  442. {
  443.     OSErr    err;
  444.  
  445.     err = HCreate(file->vRefNum, file->parID, file->name, gameCreator, theFileType);
  446.     if (err == dupFNErr) {
  447.  
  448.         /* The user already told Standard File to replace the old file
  449.            so let's get rid of it. */
  450.  
  451.         HDelete(file->vRefNum, file->parID, file->name);
  452.  
  453.         /* Try creating it again. */
  454.         err = HCreate(file->vRefNum, file->parID, file->name, gameCreator, theFileType);
  455.     }
  456.  
  457.     if (!err) {
  458.         err = HOpen(file->vRefNum, file->parID, file->name, fsRdWrPerm, refNum);
  459.         if (err)
  460.             HDelete(file->vRefNum, file->parID, file->name);
  461.     }
  462.  
  463.     return(err);
  464. }
  465.  
  466.  
  467.  
  468. /*****************************************************************************/
  469.  
  470.  
  471.  
  472. /* DisplayGetFile
  473. **
  474. ** Simple routine to display a list of files with our file type. */
  475.  
  476. #pragma segment File
  477. Boolean DisplayGetFile(StandardFileReply *reply)
  478. {
  479.     SFTypeList    typeList = {gameFileType, mssgFileType, typeChar};
  480.     Point        where = {100, 100};
  481.     SFReply        oldReply;
  482.  
  483.     if (gSystemVersion >= 0x0700)    /* If new standard file available... */
  484.         StandardGetFile(nil, 3, typeList, reply);
  485.  
  486.     else {
  487.         SFGetFile(where, "\pSelect a document to open.",
  488.                          nil, 3, typeList, nil, &oldReply);
  489.  
  490.         ConvertOldToNewSFReply(&oldReply, reply);
  491.     }
  492.  
  493.     return(reply->sfGood);
  494. }
  495.  
  496.  
  497.  
  498. /*****************************************************************************/
  499.  
  500.  
  501.  
  502. /* DisplayPutFile
  503. **
  504. ** Displays the StandardFile PutFile dialog box. Fills out the passed reply
  505. ** record, and returns the sfGood field as a result. */
  506.  
  507. #pragma segment File
  508. Boolean DisplayPutFile(StandardFileReply *reply)
  509. {
  510.     Str255        prompt;
  511.     Point        where = {100, 100};
  512.     SFReply        oldReply;
  513.  
  514.     GetIndString(prompt, rMiscStrings, ksSFprompt);
  515.  
  516.     if (gSystemVersion >= 0x0700)    /* If new standard file available... */
  517.         StandardPutFile(prompt, reply->sfFile.name, reply);
  518.     else {
  519.         SFPutFile(where, prompt, reply->sfFile.name, nil, &oldReply);
  520.         ConvertOldToNewSFReply(&oldReply, reply);
  521.     }
  522.  
  523.     return(reply->sfGood);
  524. }
  525.  
  526.  
  527.  
  528. /*****************************************************************************/
  529.  
  530.  
  531.  
  532. #pragma segment File
  533. void    IncNewFileNum(Boolean flag)
  534. {
  535.     gIncNewFileNumFlag = flag;
  536. }
  537.  
  538.  
  539.  
  540. /*****************************************************************************/
  541. /*****************************************************************************/
  542. /*****************************************************************************/
  543.  
  544.  
  545.  
  546. /* AppReadDocument
  547. **
  548. ** Reads in specified file into the data portion of a document handle. */
  549.  
  550. #pragma segment File
  551. OSErr    AppReadDocument(FileRecHndl frHndl, OSType ftype)
  552. {
  553.     short            fileRefNum, vers, i;
  554.     OSErr            err;
  555.     char            hstate;
  556.     Ptr                ptr1, ptr2;
  557.     long            count;
  558.     GameListHndl    gameMovesHndl;
  559.     Handle            textHndl;
  560.  
  561.     fileRefNum = (*frHndl)->fileState.refNum;
  562.  
  563.     err = SetFPos(fileRefNum, fsFromStart, 0);
  564.         /* Set the file position to the beginning of the file. */
  565.  
  566.     if (ftype != typeChar) {
  567.         if (!err) {        /* Read board info from file. */
  568.             hstate = LockHandleHigh((Handle)frHndl);
  569.             ptr1   = (Ptr)&((*frHndl)->doc);
  570.             ptr2   = (Ptr)&((*frHndl)->doc.endFileInfo1);
  571.             count  = (long)ptr2 - (long)ptr1;
  572.             err    = FSRead(fileRefNum, &count, ptr1);
  573.             HSetState((Handle)frHndl, hstate);
  574.             vers = (*frHndl)->doc.version;
  575.             if ((vers > kVersion) | (vers < kLeastVersion)) err = vers;
  576.         }
  577.  
  578.         if (!err) {
  579.             switch (vers) {
  580.                 case kLeastVersion:
  581.                     (*frHndl)->doc.version = kVersion;
  582.                     break;
  583.                 case kVersion:
  584.                     hstate = LockHandleHigh((Handle)frHndl);
  585.                     ptr1   = (Ptr)&((*frHndl)->doc.reconnectZone);
  586.                     ptr2   = (Ptr)&((*frHndl)->doc.endFileInfo2);
  587.                     count  = (long)ptr2 - (long)ptr1;
  588.                     err    = FSRead(fileRefNum, &count, ptr1);
  589.                     HSetState((Handle)frHndl, hstate);
  590.                     (*frHndl)->doc.compMovesWhite = (*frHndl)->doc.keepCMWhite;
  591.                     (*frHndl)->doc.compMovesBlack = (*frHndl)->doc.keepCMBlack;
  592.                     if ((*frHndl)->doc.timeLeft[0] != -1)
  593.                         for (i = 0; i < 2; ++i)
  594.                             (*frHndl)->doc.timeLeft[i] = (*frHndl)->doc.defaultTime[i];
  595.                     break;
  596.             }
  597.         }
  598.  
  599.         if (!err) {        /* Read move info from file. */
  600.             gameMovesHndl = (*frHndl)->doc.gameMoves;
  601.             count         = (*frHndl)->doc.numGameMoves * sizeof(GameElement);
  602.             SetHandleSize((Handle)gameMovesHndl, count);
  603.             err = MemError();
  604.             if (!err) {
  605.                 hstate = LockHandleHigh((Handle)gameMovesHndl);
  606.                 err = FSRead(fileRefNum, &count, (Ptr)(*gameMovesHndl));
  607.                 HSetState((Handle)gameMovesHndl, hstate);
  608.                 (*frHndl)->doc.timerRefTick = TickCount();
  609.                 (*frHndl)->doc.displayTime[0] = -1;
  610.                 (*frHndl)->doc.displayTime[1] = -1;
  611.                 (*frHndl)->doc.freezeTime[0] = -1;
  612.                 (*frHndl)->doc.freezeTime[1] = -1;
  613.                 (*frHndl)->fileState.docDirty = false;
  614.                 if (!err)
  615.                     if ((*frHndl)->doc.version != kVersion)
  616.                         err = kWrongVersion;
  617.             }
  618.         }
  619.     }
  620.  
  621.     if (!err) {        /* Read TextEdit text from file. */
  622.         textHndl = (Handle)(*frHndl)->doc.legalMoves;
  623.             /* There may be text saved to the file.  If there is any, this text
  624.             ** belongs in the out-box TextEdit control.  AppNewWindow creates
  625.             ** this control.  The problem is that a document is read before the
  626.             ** window for it is created.  Therefore the text will be placed
  627.             ** temporarily in the legalMoves handle.  Once GenerateLegalMoves
  628.             ** is called, the content of this handle will be overwritten.
  629.             ** GenereteLegalMoves isn't called until the window is created, so
  630.             ** this is an easy way to pass the text to AppNewWindow. */
  631.         count = 32000;
  632.             /* The size of the text isn't saved to disk.  This is the maximum
  633.             ** that we will accept. */
  634.         SetHandleSize(textHndl, count);
  635.         if (!(err = MemError())) {
  636.             hstate = LockHandleHigh(textHndl);
  637.             err    = FSRead(fileRefNum, &count, *textHndl);
  638.             HSetState((Handle)frHndl, hstate);
  639.             if (err == eofErr) err = noErr;
  640.             if (err) count = 0;
  641.             SetHandleSize(textHndl, count);
  642.                 /* Set the handle to the actual size of the text on disk. */
  643.         }
  644.     }
  645.  
  646.     return(err);
  647. }
  648.  
  649.  
  650.  
  651. /*****************************************************************************/
  652.  
  653.  
  654.  
  655. /* AppWriteDocument
  656. **
  657. ** Writes the data portion of a document handle to the specified file. */
  658.  
  659. #pragma segment File
  660. OSErr    AppWriteDocument(FileRecHndl frHndl)
  661. {
  662.     short            fileRefNum;
  663.     OSErr            err;
  664.     char            hstate;
  665.     Ptr                ptr1, ptr2;
  666.     long            count, fpos;
  667.     GameListHndl    gameMovesHndl;
  668.     TEHandle        te;
  669.     Handle            textHndl;
  670.     WindowPtr        window;
  671.     short            width;
  672.  
  673.     fileRefNum = (*frHndl)->fileState.refNum;
  674.  
  675.     err = SetFPos(fileRefNum, fsFromStart, 0);
  676.         /* Set the file position to the beginning of the file. */
  677.  
  678.     if (!err) {        /* Write board info to file. */
  679.         hstate = LockHandleHigh((Handle)frHndl);
  680.         ptr1   = (Ptr)&((*frHndl)->doc);
  681.         ptr2   = (Ptr)&((*frHndl)->doc.endFileInfo1);
  682.         count  = (long)ptr2 - (long)ptr1;
  683.         err    = FSWrite(fileRefNum, &count, ptr1);
  684.         HSetState((Handle)frHndl, hstate);
  685.     }
  686.  
  687.     if (!err) {        /* Write board info to file. */
  688.         hstate = LockHandleHigh((Handle)frHndl);
  689.         (*frHndl)->doc.reconnectZone[0]    = 0;
  690.         (*frHndl)->doc.reconnectMachine[0] = 0;
  691.         if ((*frHndl)->doc.twoPlayer) {
  692.             pcpy((*frHndl)->doc.reconnectZone,    (*frHndl)->doc.opponentZone);
  693.             pcpy((*frHndl)->doc.reconnectMachine, (*frHndl)->doc.opponentMachine);
  694.         }
  695.         (*frHndl)->doc.justBoardWindow = false;
  696.         window = (*frHndl)->fileState.window;
  697.         if (window) {
  698.             width = window->portRect.right - window->portRect.left;
  699.             if (width == rJustBoardWindowWidth) (*frHndl)->doc.justBoardWindow = true;
  700.         }
  701.         (*frHndl)->doc.keepCMWhite = (*frHndl)->doc.compMovesWhite;
  702.         (*frHndl)->doc.keepCMBlack = (*frHndl)->doc.compMovesBlack;
  703.         ptr1  = (Ptr)&((*frHndl)->doc.reconnectZone);
  704.         ptr2  = (Ptr)&((*frHndl)->doc.endFileInfo2);
  705.         count = (long)ptr2 - (long)ptr1;
  706.         err   = FSWrite(fileRefNum, &count, ptr1);
  707.         HSetState((Handle)frHndl, hstate);
  708.     }
  709.  
  710.     if (!err) {        /* Write move info to file. */
  711.         gameMovesHndl = (*frHndl)->doc.gameMoves;
  712.         count         = (*frHndl)->doc.numGameMoves * sizeof(GameElement);
  713.         hstate = LockHandleHigh((Handle)gameMovesHndl);
  714.         err = FSWrite(fileRefNum, &count, (Ptr)(*gameMovesHndl));
  715.         HSetState((Handle)gameMovesHndl, hstate);
  716.     }
  717.  
  718.     if (!err) {        /* Write out-box TextEdit control text to file. */
  719.         te       = (*frHndl)->doc.message[kMessageOut];
  720.         textHndl = (*te)->hText;
  721.         count    = (*te)->teLength;
  722.         hstate   = LockHandleHigh(textHndl);
  723.         err      = FSWrite(fileRefNum, &count, *textHndl);
  724.         HSetState(textHndl, hstate);
  725.     }
  726.  
  727.     if (!err) {
  728.         err = GetFPos(fileRefNum, &fpos);
  729.         if (!err) err = SetEOF(fileRefNum, fpos);
  730.     }
  731.  
  732.     return(err);
  733. }
  734.  
  735.  
  736.  
  737. /*****************************************************************************/
  738.  
  739.  
  740.  
  741. #pragma segment File
  742. OSErr    AppDuplicateDocument(FileRecHndl oldFrHndl, FileRecHndl *newFrHndl)
  743. {
  744.     OSErr            err;
  745.     GameListHndl    oldMoves, newMoves;
  746.     Ptr                ptr1, ptr2;
  747.     long            oldMovesSize, dataSize;
  748.     Handle            oldText, newText;
  749.     TEHandle        te;
  750.     short            winNameType;
  751.  
  752.     winNameType = ksOrigName;
  753.     if ((*oldFrHndl)->doc.myColor == kMessageDoc) winNameType = ksMssgName;
  754.  
  755.     err = AppNewDocument(newFrHndl, winNameType);
  756.     if (!err) {
  757.         oldMoves = (*oldFrHndl)->doc.gameMoves;
  758.         newMoves = (**newFrHndl)->doc.gameMoves;
  759.         oldMovesSize = GetHandleSize((Handle)oldMoves);
  760.         SetHandleSize((Handle)newMoves, oldMovesSize);
  761.         err = MemError();
  762.         if (!err) {
  763.             ptr1     = (Ptr)&((*oldFrHndl)->doc);
  764.             ptr2     = (Ptr)&((*oldFrHndl)->doc.endFileInfo1);
  765.             dataSize = (long)ptr2 - (long)ptr1;
  766.             ptr2     = (Ptr)&((**newFrHndl)->doc);
  767.             BlockMove(ptr1, ptr2, dataSize);
  768.             (**newFrHndl)->doc.timeLeft[0] = (**newFrHndl)->doc.timeLeft[1] = -1;
  769.             BlockMove((Ptr)*oldMoves, (Ptr)*newMoves, oldMovesSize);
  770.             if ((*oldFrHndl)->doc.myColor == kMessageDoc) {
  771.                 te = (*oldFrHndl)->doc.message[kMessageOut];
  772.                 oldText = (*te)->hText;
  773.                 newText = (Handle)(**newFrHndl)->doc.legalMoves;
  774.                 SetHandleSize(newText, (*te)->teLength);
  775.                 err = MemError();
  776.                 if (!err) BlockMove(*oldText, *newText, (*te)->teLength);
  777.             }
  778.         }
  779.     }
  780.     return(err);
  781. }
  782.  
  783.  
  784.  
  785. /*****************************************************************************/
  786.  
  787.  
  788.  
  789. #pragma segment File
  790. OSErr    AppAutoLaunch(FileRecHndl frHndl)
  791. {
  792.     OSErr            err;
  793.     AEDesc            remoteDesc, aeDirDesc, listElem, fileList;
  794.     AppleEvent        aevt, aeReply;
  795.     char            hstate;
  796.     Str255            path;
  797.     Str255            app;
  798.     AliasHandle        dirAlias, fileAlias;
  799.  
  800.     err = noErr;
  801.  
  802.     if ((*frHndl)->doc.reconnectZone[0]) {
  803.  
  804.         DoSetCursor(*GetCursor(watchCursor));
  805.  
  806.         if (!GetRemoteProcessTarget(frHndl, &remoteDesc, FinderFilter)) {
  807.  
  808.             err = AECreateAppleEvent('FNDR', 'sope', &remoteDesc,
  809.                                       kAutoGenerateReturnID, kAnyTransactionID, &aevt);
  810.             AEDisposeDesc(&remoteDesc);
  811.  
  812.             if (!err) {
  813.  
  814.                 hstate = LockHandleHigh((Handle)frHndl);
  815.                 pcpy(path, (*frHndl)->doc.reconnectPath);
  816.                 pcpy(app, path);
  817.                 pcat(app,  (*frHndl)->doc.reconnectApp);
  818.                 HSetState((Handle)frHndl, hstate);
  819.                 NewAliasMinimalFromFullPath(path[0], (path + 1), "\p", "\p", &dirAlias);
  820.                 NewAliasMinimalFromFullPath(app[0],  (app + 1),  "\p", "\p", &fileAlias);
  821.  
  822.                 err = AECreateList(nil, 0, false, &fileList);
  823.  
  824.                 if (!err) {
  825.                     hstate = LockHandleHigh((Handle)dirAlias);
  826.                     err = AECreateDesc(typeAlias, (Ptr)*dirAlias,
  827.                                        GetHandleSize((Handle)dirAlias), &aeDirDesc);
  828.                     HSetState((Handle)dirAlias, hstate);
  829.                 }
  830.                 DisposeHandle((Handle)dirAlias);
  831.  
  832.                 if (!err) {
  833.                     err = AEPutParamDesc(&aevt, keyDirectObject, &aeDirDesc);
  834.                     AEDisposeDesc(&aeDirDesc);
  835.                 }
  836.  
  837.                 if (!err) {
  838.                     hstate = LockHandleHigh((Handle)fileAlias);
  839.                     err = AECreateDesc(typeAlias, (Ptr)*fileAlias,
  840.                                        GetHandleSize((Handle)fileAlias), &listElem);
  841.                     HSetState((Handle)dirAlias, hstate);
  842.                 }
  843.                 DisposeHandle((Handle)fileAlias);
  844.  
  845.                 if (!err) {
  846.                     err = AEPutDesc(&fileList, 0, &listElem);
  847.                     AEDisposeDesc(&listElem);
  848.                 }
  849.  
  850.                 if (!err) {
  851.                     err = AEPutParamDesc(&aevt, 'fsel', &fileList);
  852.                     AEDisposeDesc(&fileList);
  853.                 }
  854.  
  855.                 if (!err) {
  856.                     err = AESend(&aevt, &aeReply,
  857.                                 (kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer),
  858.                                 kAENormalPriority, kAEDefaultTimeout, nil, nil);
  859.                     AEDisposeDesc(&aeReply);
  860.                 }
  861.  
  862.                 AEDisposeDesc(&aevt);
  863.  
  864.                 if (!err) SendGame(frHndl, kIsMove, "\pKibitz");
  865.  
  866.             }
  867.         }
  868.     }
  869.  
  870.     return(err);
  871. }
  872.  
  873.  
  874.  
  875.